package models

import (
	"fmt"
	"gitee.com/lzqysoft/ims/libs/fsm"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"time"
)

const (
	FLOWINSTANCE        = "FLOWINSTANCE"
	TRANSITION_INSTANCE = "TRANSITION_INSTANCE"
	USER                = "USER"
	OPTION              = "OPTION"
	REMAEK              = "REMAEK"
	RESULT              = "RESULT"
	ACTOIN              = "ACTOIN"
	EVENT               = "EVENT"
	BUSY_TABLE          = "BUSY_TABLE"
	BUSY_ID             = "BUSY_ID"
	TARGET              = "TARGET"
	KEY                 = "KEY"
	VALUE               = "VALUE"
	TYPE                = "TYPE"
	TO                  = "TO"
	FROM                = "FROM"
)

type FlowProcessor struct{}

// OnExit 离开fromstate时的动作。
func (p *FlowProcessor) OnExit(fromState string, args map[string]interface{}) {
	//t := args[0].(*Flowinstance)
	//// if t.Currentstate != fromState {
	//// 	panic(fmt.Errorf("流程 %v 的状态与期望的状态 %s 不一致，可能在状态机外被改变了", t, fromState))
	//// }
	//beego.Debug("流程 ", t.Name, " 从状态 ", fromState, " 改变")
}

// Action 流程转换被处理的时候，状态机会执行特定的动作，
// 比如改变变量、执行I/O、调用方法、触发另一个事件等。
// 此处流程动作为向to流程责任人发送信息，from状态为2,to状态为1
// 若to类型为end，将流程实例状态改为2,标识已完成
func (p *FlowProcessor) Action(action, fromState, toState string, args map[string]interface{}) {
	flow := getFlowinstanceFromArgs(args)
	user := getUserFromArgs(args)
	//opinions := getOptionsFromArgs(args)
	remark := getRemarkFromArgs(args)
	result := getResultFromArgs(args)
	from, _ := GetStateinstanceById(fromState)
	to, _ := GetStateinstanceById(toState)
	o := orm.NewOrm()
	o.Begin()
	//if from.Classname == "start" {
	//	flow.Status = 3
	//}

	//if to.Classname == "end" {}
	//变更from 与 to的struct字段与其它相关信息
	to.Status = 1
	to.Utime = time.Now()
	from.Status = 2
	//from.Opinions = opinions
	from.Remark = remark
	from.Utime = time.Now()
	from.Approver = user.Abbr
	from.Atime = time.Now()
	from.Result = result
	//from.Result =

	if _, err := o.Update(from); err != nil {
		beego.Debug(err)
		o.Rollback()
		return
	}
	if _, err := o.Update(to); err != nil {
		beego.Debug(err)
		o.Rollback()
		return
	}
	// 变更flowinstance 的当前状态
	flow.Currentstate = to.Id
	if _, err := o.Update(flow); err != nil {
		beego.Debug(err)
		o.Rollback()
		return
	}

	actionIns, err := GetActionById(action)
	if err != nil {
		beego.Debug(err)
		o.Rollback()
		return
	}
	// 变更同源StateInstance但不是to
	if actionIns.Name != "会签" && actionIns.Name != "分派" {
		if err := UpdateOtherStateInstanceStatusTo3(o, fromState, toState); err != nil {
			beego.Debug(err)
			o.Rollback()
			return
		}
	}
	// 变更当前transition状态为2， to 相同的其它transition状态为3
	if err := UpdateTransitionByIdAndTo(o, getCurrentTransitionInstanceFromArgs(args), fromState); err != nil {
		beego.Debug(err)
		o.Rollback()
		return
	}
	// 触发action
	args[TO] = to
	args[FROM] = from
	args[ACTOIN] = action
	if err := TiggerAction(o, action, args); err != nil {
		beego.Debug(err)
		o.Rollback()
		return
	}
	o.Commit()
	beego.Info("流程 ", flow.Name, " 的状态从 ", from.Text, " 改变为  ", to.Text)
}

// OnEnter 进入一个状态，可以执行的动作,此处添加提醒消息
// 添加下一步的stateinstance和transtation, 并判断是否自动tigger
func (p *FlowProcessor) OnEnter(toState string, args map[string]interface{}) {
	stateIns := getToStateInstanceFromArgs(args)

	flow := getFlowinstanceFromArgs(args)
	f, _ := GetFlowinstanceById(flow.Id)

	flow.Currentstate = stateIns.Id
	orm.NewOrm().Update(flow)

	beego.Debug("toState", toState)
	// 自动任务，任务分派，任务汇聚，任务指派 对应不同的 处理方式，在此处理
	switch stateIns.Classname {
	case "end":
		beego.Debug("结束")
		f.Status = 2
		//if _, err := orm.NewOrm().QueryTable(flow.Busyname).Filter("Id", flow.Busyid).Update(orm.Params{
		//	"Status": 3,
		//	//"Result": flag,
		//}); err != nil {
		//	beego.Debug(err)
		//	//return err
		//}
		SetBusyEnd(flow.Busyid, flow.Busyname, 1)
	case "start":
		beego.Debug("开始")
		f.Status = 3
		// 项目被退回
		if _, err := orm.NewOrm().QueryTable(flow.Busyname).Filter("Id", flow.Busyid).Update(orm.Params{
			"Type": orm.ColValue(orm.ColMinus, 1),
			//"Status": 2,
			//"Result": flag,
		}); err != nil {
			beego.Debug(err)
			//return err
		}
	case "fork":
		beego.Debug("分派任务")
		// f.Currentstate = toState
		beego.Debug(stateIns)
		fs := GetFsmStateMachine(f)
		ev, err := GetEventByName("分派")
		if err != nil {
			beego.Debug(err)
		}
		err = fs.Trigger(stateIns.Id, ev.Id, args)
		if err != nil {
			beego.Error("分派 err: ", err)
		}
	case "join":
		beego.Debug("汇聚任务")
		//beego.Debug(toState)
		ts, _ := GetFromByFork(toState)
		agree, disagree := 0, 0
		for _, k := range ts {
			tins, err := GetStateinstanceById(k.From)
			if err != nil {
				beego.Debug(err)
				return
			}
			beego.Debug(fmt.Sprintf("会签审核结果：Text-> %v, Status-> %v, Result-> %v", tins.Text, tins.Status, tins.Result))
			if tins.Status == 2 {
				switch tins.Result {
				case 0:
					disagree++
				case 1:
					agree++
				default:

				}
				beego.Debug(fmt.Sprintf("Result(%v), Type(%T)", tins.Result, tins.Result))
				//if (tins.Result == 1) {
				//	agree++
				//} else {
				//	disagree++
				//}
			}
		}

		// 如果都审批了
		if agree+disagree == len(ts) {
			beego.Debug(fmt.Sprintf("agree(%v)+disagree(%v) == len(ts)(%v)", agree, disagree, len(ts)))
			beego.Debug("分派的任务审批结束，进入判断 ")
			// TODO
			beego.Debug("当前进入下一步的条件是全部同意,可在此处修改 ")
			//if agree == len(ts) {
			//	beego.Debug("聚合同意=============== ")
			//	fs := GetFsmStateMachine(f)
			//	ev, _ := GetEventByName("同意")
			//	err := fs.Trigger(toState, ev.Id, args)
			//	if err != nil {
			//		beego.Error("聚合同意 err: ", err)
			//	}
			//} else {
			//	beego.Debug("聚合不同意=============== ")
			//	fs := GetFsmStateMachine(f)
			//	ev, _ := GetEventByName("不同意")
			//	err := fs.Trigger(toState, ev.Id, args)
			//	if err != nil {
			//		beego.Error("聚合不同意 err: ", err)
			//	}
			//}
			fs := GetFsmStateMachine(f)
			ev, _ := GetEventByName("同意")
			err := fs.Trigger(toState, ev.Id, args)
			if err != nil {
				beego.Error("聚合同意 err: ", err)
			}

		} else {
			beego.Debug("分派的任务未审批结束，等待中... ")
		}
	case "auto":
		beego.Debug("自动任务")
		//fs := GetFsmStateMachine(f)
		//fs.
		//if f.Busyname == "sf_case" {
		//	fsCase, _ := GetSfCaseById(f.Busyid)
		//	//if err != nil {
		//	//	beego.Error("自动任务", err)
		//	//}
		//	if fsCase.IsAdditional != 1 {
		//		//  检验预约自动任务
		//		ev, _ := GetEventByName("否")
		//		fs.Trigger(toState, ev.Id, args)
		//	} else {
		//		ev, _ := GetEventByName("是")
		//		//  检验补充送检预约自动任务
		//		fs.Trigger(toState, ev.Id, args)
		//	}
		//}
		beego.Debug("自动任务")
		fs := GetFsmStateMachine(f)
		event, _ := GetEventByName("自动")
		fs.Trigger(toState, event.Id, args)
		//if f.Busyname == "sf_case" {
		//	fsCase, _ := GetSfCaseById(f.Busyid)
		//	//if err != nil {
		//	//	beego.Error("自动任务", err)
		//	//}
		//	if fsCase.IsAdditional != 1 {
		//		//  检验预约自动任务
		//		ev, _ := GetEventByName("否")
		//		fs.Trigger(toState, ev.Id,args)
		//	} else {
		//		ev, _ := GetEventByName("是")
		//		//  检验补充送检预约自动任务
		//		fs.Trigger(toState, ev.Id, args...)
		//	}
		//}
	}

}

func GetFsmStateMachine(flowins *Flowinstance) *fsm.FsmStateMachine {
	delegate := &fsm.FsmDelegate{P: &FlowProcessor{}}
	//beego.Debug(flowins.Flow)
	t, err := GetTransitionInstanceByFlow(flowins.Id)
	transitions := []fsm.Transition{}
	if err != nil {
		return nil
	}
	beego.Debug("len(transition)", len(t))
	for _, u := range t {
		var f fsm.Transition
		f.From = u["From"].(string)
		f.To = u["To"].(string)
		f.Action = u["Action"].(string)
		f.Event = u["Event"].(string)
		f.FromName = u["FromName"].(string)
		f.ToName = u["ToName"].(string)
		f.ActionName = u["ActionName"].(string)
		f.EventName = u["EventName"].(string)
		f.Id = u["Id"].(string)
		transitions = append(transitions, f)
	}
	return fsm.NewFsmStateMachine(delegate, transitions...)
}

func getFlowinstanceFromArgs(args map[string]interface{}) *Flowinstance {
	data, ok := args[FLOWINSTANCE]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return nil
	}
	flowIns, ok := data.(*Flowinstance)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return nil
	}
	return flowIns
}

func getUserFromArgs(args map[string]interface{}) *User {
	data, ok := args[USER]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return nil
	}
	user, ok := data.(*User)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return nil
	}
	return user
}

func getOptionsFromArgs(args map[string]interface{}) string {
	data, ok := args[OPTION]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return ""
	}
	options, ok := data.(string)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return ""
	}
	return options
}

func getRemarkFromArgs(args map[string]interface{}) string {
	data, ok := args[REMAEK]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return ""
	}
	remark, ok := data.(string)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return ""
	}
	return remark
}
func getCurrentTransitionInstanceFromArgs(args map[string]interface{}) string {
	data, ok := args[TRANSITION_INSTANCE]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return ""
	}
	remark, ok := data.(string)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return ""
	}
	return remark
}
func getResultFromArgs(args map[string]interface{}) int {
	data, ok := args[RESULT]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return 0
	}
	remark, ok := data.(int)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return 0
	}
	return remark
}

func getToStateInstanceFromArgs(args map[string]interface{}) *Stateinstance {
	data, ok := args[TO]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return nil
	}
	flowIns, ok := data.(*Stateinstance)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return nil
	}
	return flowIns
}

func getFromStateInstanceFromArgs(args map[string]interface{}) *Stateinstance {
	data, ok := args[FROM]
	if !ok {
		beego.Debug("ARGS KEY 值设置有误！")
		return nil
	}
	flowIns, ok := data.(*Stateinstance)
	if !ok {
		beego.Debug("ARGS value 值设置有误！")
		return nil
	}
	return flowIns
}

// 审批触发的动作
// action 记录与 func 对应
// 根据action 生成 一下部stateins和transins
func TiggerAction(o orm.Ormer, actionId string, args map[string]interface{}) error {
	action, _ := GetActionById(actionId)
	flow := getFlowinstanceFromArgs(args)
	toState := getToStateInstanceFromArgs(args)

	user := getUserFromArgs(args)
	beego.Debug("ACTION=====================", action.Key)
	switch action.Key {
	//提醒
	case "MESSAGE":
		if toState.Classname != "join" {
			beego.Debug(toState)
			if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user, args); err != nil {
				beego.Debug(err)
				//o.Rollback()
				return err
			}
		}
		return NewMessageWithTransaction(o, flow, toState)
		// 分派
	case "FORK":
		//if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user);err != nil {
		//	beego.Debug(err)
		//	//o.Rollback()
		//	return err
		//}
		return NewMessageWithTransaction(o, flow, toState)

		// 汇聚
	case "JOIN":
		//if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user);err != nil {
		//	beego.Debug(err)
		//	o.Rollback()
		//	return err
		//}
		return NewMessageWithTransaction(o, flow, toState)

		// 归档
	case "FILE":
		//if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user);err != nil {
		//	beego.Debug(err)
		//	//o.Rollback()
		//	return err
		//}
		tid := args[TRANSITION_INSTANCE].(string)
		trans, err := GetTransitionInstanceById(tid)
		if err != nil {
			beego.Debug(err)
			return err
		}
		trans.Status, trans.Utime = 2, time.Now()
		toState.Status = 2
		flow.Status = 3
		flow.Currentstate = toState.Id
		if _, err := o.Update(toState); err != nil {
			beego.Debug(err)
			return err
		}
		if _, err := o.Update(flow); err != nil {
			beego.Debug(err)
			return err
		}
		//flag := 0
		//if trans.Name == "同意" {
		//	flag = 1
		//}
		// 将业务表标记为完成状态
		if _, err := o.QueryTable(flow.Busyname).Filter("Id", flow.Busyid).Update(orm.Params{
			"Type": orm.ColValue(orm.ColAdd, 1),
			//"Result": flag,
		}); err != nil {
			beego.Debug(err)
			return err
		}
		//o.Update(flow)
		return NewMessageWithTransaction(o, flow, toState)
		// 冻结
	case "FREEZE":
		if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user, args); err != nil {
			beego.Debug(err)
			//o.Rollback()
			return err
		}
		return NewMessageWithTransaction(o, flow, toState)
		// 暂停
	case "PAUSE":
		if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user, args); err != nil {
			beego.Debug(err)
			//o.Rollback()
			return err
		}
		return NewMessageWithTransaction(o, flow, toState)
		// 指派
	case "DISPATCH":
		// 生成下一步stateInsatence与tarnsition
		// 只有一条
		//if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user);err != nil {
		//	beego.Debug(err)
		//	o.Rollback()
		//	return err
		//}
		if err := DispatchAction(o, flow, toState, user, args); err != nil {
			beego.Debug(err)
			o.Rollback()
			return err
		}
		return NewMessageWithTransaction(o, flow, toState)
		// 选择
	case "SELECT":
		if err := SelectActionHandler(o, args); err != nil {
			beego.Debug(err)
			//o.Rollback()
			return err
		}
		return NewMessageWithTransaction(o, flow, toState)
	// 开始
	case "GROUP":
		if err := GroupActionHandler(o, args); err != nil {
			beego.Debug(err)
			//o.Rollback()
			return err
		}
		return NewMessageWithTransaction(o, flow, toState)
	case "START":
		if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user, args); err != nil {
			beego.Debug(err)
			//o.Rollback()
			return err
		}
		return NewMessageWithTransaction(o, flow, toState)
		// 启动 与暂停对应
	case "LAUNCH":
		if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user, args); err != nil {
			beego.Debug(err)
			//o.Rollback()
			return err
		}
		return NewMessageWithTransaction(o, flow, toState)
	case "CHANGE":
		// 项目变更
		beego.Debug("// 项目变更")
		pf, err := GetImsProjectByIdNoRel(flow.Busyid)
		if err != nil {
			return err
		}
		if _, err := o.QueryTable(new(ImsProject)).Filter("Id", pf.Remark).Update(orm.Params{
			"Name":        pf.Name,
			"SubjectId":   pf.SubjectId,
			"SubjectName": pf.SubjectName,
			"Start":       pf.Start,
			"End":         pf.End,
			"TutorId":     pf.TutorId,
			"TutorName":   pf.TutorName,
			"WordUrl":     pf.WordUrl,
			"Md5":         pf.Md5,
			"Content":     pf.Content,
			"Schedule":    pf.Schedule,
			"Scheme":      pf.Scheme,
			"Budget":      pf.Budget,
			"Used":        pf.Used,
			//"ProfessorGroupId": pf.P
			"DeptName":     pf.DeptName,
			"Desc":         pf.Desc,
			"Reason":       pf.Reason,
			"SheduleTable": pf.SheduleTable,
			"Expect":       pf.Expect,
			"GroupDetail":  pf.GroupDetail,
			"Analysis":     pf.Analysis,
			"Benefit":      pf.Benefit,
			"TutorDetail":  pf.TutorDetail,
			"Place":        pf.Place,
			"Step":         pf.Step,
		}); err != nil {
			beego.Debug(err)
			return err
		}
		// remove before tutor, group, attach, budget
		if _, err := o.QueryTable(new(ImsProjectGroup)).Filter("project_id", pf.Remark).Delete(); err != nil {
			beego.Debug(err)
			return err
		}
		if _, err := o.QueryTable(new(ImsTotur)).Filter("project_id", pf.Remark).Delete(); err != nil {
			beego.Debug(err)
			return err
		}
		if _, err := o.QueryTable(new(ImsProjectAttachment)).Filter("project_id", pf.Remark).Delete(); err != nil {
			beego.Debug(err)
			return err
		}
		if _, err := o.QueryTable(new(ImsBudget)).Filter("project_id", pf.Remark).Delete(); err != nil {
			beego.Debug(err)
			return err
		}
		// update after tutor, group, attach, budget
		if _, err := o.QueryTable(new(ImsProjectGroup)).Filter("project_id", pf.Id).Update(orm.Params{
			"project_id": pf.Remark,
		}); err != nil {
			beego.Debug(err)
			return err
		}
		if _, err := o.QueryTable(new(ImsTotur)).Filter("project_id", pf.Id).Update(orm.Params{
			"project_id": pf.Remark,
		}); err != nil {
			beego.Debug(err)
			return err
		}
		if _, err := o.QueryTable(new(ImsProjectAttachment)).Filter("project_id", pf.Id).Update(orm.Params{
			"project_id": pf.Remark,
		}); err != nil {
			beego.Debug(err)
			return err
		}
		if _, err := o.QueryTable(new(ImsBudget)).Filter("project_id", pf.Id).Update(orm.Params{
			"project_id": pf.Remark,
		}); err != nil {
			beego.Debug(err)
			return err
		}
		return nil
	case "GENERATE":
		// 生成成果物

		beego.Debug("暂未生成成果物！")
		beego.Debug("生成成果物信息可在此处修改！")
		beego.Debug("该需求尚不明确，暂不实现！")
		// 标记为已结项
		if _, err := o.QueryTable(flow.Busyname).Filter("Id", flow.Busyid).Update(orm.Params{
			"Type": orm.ColValue(orm.ColAdd, 1),
			//"Result": flag,
		}); err != nil {
			beego.Debug(err)
			return err
		}
		return nil
	case "CALCULATE":
		//  CALCULATE
		beego.Debug("=================此处为自动任务触发事件=====================")
		beego.Debug("=================TODO=====================")
		// TODO 此处为自动任务触发事件

		beego.Debug("=================TODO=====================")
		beego.Debug("=================此处为自动任务触发事件=====================")

		return ColculateAction(o, flow, toState, user, args)
	default:
		if err := autoGenerateStateInstanceAndTransitionInstance(o, flow, toState, user, args); err != nil {
			beego.Debug(err)
			//o.Rollback()
			return err
		}
		beego.Debug("ACTION空，不执行任何动作")
		return nil
	}
}

func FlowApprove(transInstance *TransitionInstance, user *User) error {
	fs, err := GetFlowinstanceById(transInstance.Flowinstance.Id)
	if err != nil {
		return err
	}
	machine := GetFsmStateMachine(fs)
	//if err = machine.Trigger(transInstance.From, transInstance.EventId, fs)
	//machine := GetFsmStateMachine(fs)
	//ev, _ := GetEventByName("上报")
	args := make(map[string]interface{})
	args[FLOWINSTANCE] = fs
	args[USER] = user
	args[OPTION] = transInstance.Opinions
	args[REMAEK] = transInstance.Remark
	args[RESULT] = transInstance.Result
	err = machine.Trigger(transInstance.From, transInstance.EventId, args)
	//err = SetBusyStart(fs.Busyid, fs.Busyname)
	if err != nil {
		beego.Error("trigger1 err: ", err)
		return err
	}
	return nil
}
